package com.pf.utils;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 案例需求描述：
 * 用户账号和密码用对称加密（AES），然后对称加密的密钥用非对称加密的公钥加密。
 * 前端将AES加密的账号密码以及 RSA公钥加密的AES密钥传给后端。后端再解密操作。（RSA的公钥和私钥是后端生成的，然后后端将公钥给前端）
 *
 * @author PanFei
 * @version 1.0.0
 * @createTime 2021/9/9
 */
public class AesAndRsaUtils {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    static class LoginUser {
        private String account;
        private String password;
        private String aesKey;
    }

    public static void main(String[] args) throws Exception {
//        testLoginData();
        testCascadeData();
    }

    /**
     * 测试用户登录，对应 com.pf.controller.DemoController#decrypt(com.pf.dto.User)
     *
     * @throws Exception
     */
    private static void testLoginData() throws Exception {
        // 前端模拟加密账号密码
        LoginUser encryptLoginUser = encryptByWeb();
        System.out.println("前端加密的用户登录信息：account=" + encryptLoginUser.getAccount() + "  >> password=" + encryptLoginUser.getPassword());
        System.out.println("前端加密的用户登录信息：rsa公钥加密后的aes密钥 secretKey=" + encryptLoginUser.getAesKey());
        LoginUser decryptLoginUser = decryptByBackGround(encryptLoginUser);
        System.out.println("后端解密的用户信息：account=" + decryptLoginUser.getAccount() + "  >> password=" + decryptLoginUser.getPassword());
    }

    /**
     * 测试级联
     *
     * @throws Exception
     */
    private static void testCascadeData() throws Exception {
        // 可调用 AesUtils.getAesKey() 方法获取一个 128位的AES密钥
        String aesKeyStr = "CC4zzmTLjQRX+tb+1DpQ/w==";
        String account = "18221177062";
        String password = "Abc12345";
        String baseName = "baseName";
        String address1 = "上海市";
        String address2 = "西安市";

        // 模拟前端将AES密钥通过RSA加密
        String aesKeyWithRsa = ERSAUtils.encrypt(aesKeyStr, ERSAUtils.getPublicKey(ERSAUtils.PUBLIC_KEY));

        // 模拟前端AES加密的账号、密码
        String accountWithAes = AESUtils.encrypt(account, aesKeyStr);
        String passwordWithAes = AESUtils.encrypt(password, aesKeyStr);
        String baseNameWithAes = AESUtils.encrypt(baseName, aesKeyStr);
        String address1WithAes = AESUtils.encrypt(address1, aesKeyStr);
        String address2WithAes = AESUtils.encrypt(address2, aesKeyStr);

        // 解密
        System.out.println(">>>>>>>>>>>>解密后...........");
        String aesKey = ERSAUtils.decrypt(aesKeyWithRsa, ERSAUtils.getPrivateKey(ERSAUtils.PRIVATE_KEY));
        String decryptAccount = AESUtils.decrypt(accountWithAes, aesKey);
        String decryptPassword = AESUtils.decrypt(passwordWithAes, aesKey);
        String decryptBaseName = AESUtils.decrypt(baseNameWithAes, aesKey);
        String decryptAddress1 = AESUtils.decrypt(address1WithAes, aesKey);
        String decryptAddress2 = AESUtils.decrypt(address2WithAes, aesKey);
        System.out.println("AES密钥用RSA加密后=" + aesKeyWithRsa);
        System.out.println("原 account=" + account + " || accountWithAes=" + accountWithAes + " || decryptAccount=" + decryptAccount);
        System.out.println("原 password=" + password + " || passwordWithAes=" + passwordWithAes + " || decryptPassword=" + decryptPassword);
        System.out.println("原 baseName=" + baseName + " || baseNameWithAes=" + baseNameWithAes + " || decryptBaseName=" + decryptBaseName);
        System.out.println("原 address1=" + address1 + " || address1WithAes=" + address1WithAes + " || decryptAddress1=" + decryptAddress1);
        System.out.println("原 address2=" + address2 + " || address2WithAes=" + address2WithAes + " || decryptAddress2=" + decryptAddress2);
    }

    /**
     * 模拟前端将账号信息加密
     * 1.账号和密码通过AES加密
     * 2.AES密钥通过RSA公钥加密（RSA的公钥和私钥是后端生成的，然后将公钥给前端）
     *
     * @return
     */
    public static LoginUser encryptByWeb() throws Exception {
        //用户账号、密码
        String account = "18221177062";
        String password = "abc123";
        System.out.println("前端用户原登录账号：account=" + account + "    >> password=" + password);
        // 可调用 AesUtils.getAesKey() 方法获取一个 128位的AES密钥
        String aesKeyStr = "CC4zzmTLjQRX+tb+1DpQ/w==";
        // 模拟前端AES加密的账号、密码
        String accountWithAes = AESUtils.encrypt(account, aesKeyStr);
        String passwordWithAes = AESUtils.encrypt(password, aesKeyStr);
        // 模拟前端将AES密钥通过RSA加密
        String aesKeyWithRsa = ERSAUtils.encrypt(aesKeyStr, ERSAUtils.getPublicKey(ERSAUtils.PUBLIC_KEY));
        return LoginUser.builder()
                .account(accountWithAes)
                .password(passwordWithAes)
                .aesKey(aesKeyWithRsa)
                .build();
    }

    /**
     * 模拟后端
     *
     * @param encryptLoginUser
     * @return
     */
    public static LoginUser decryptByBackGround(LoginUser encryptLoginUser) throws Exception {
        String aesKey = ERSAUtils.decrypt(encryptLoginUser.getAesKey(), ERSAUtils.getPrivateKey(ERSAUtils.PRIVATE_KEY));
        String account = AESUtils.decrypt(encryptLoginUser.getAccount(), aesKey);
        String password = AESUtils.decrypt(encryptLoginUser.getPassword(), aesKey);
        encryptLoginUser.setAccount(account);
        encryptLoginUser.setPassword(password);
        return encryptLoginUser;
    }
}
